package scrumtaculous.domain;

import java.util.StringTokenizer;

import org.apache.commons.lang.builder.ToStringBuilder;

public abstract class DataTransferObject implements Comparable<DataTransferObject>
{

   public abstract Integer getId();

   public abstract void setId(Integer idIn);

   public abstract Integer getVersion();

   public abstract void setVersion(Integer versionIn);

   public boolean isNew()
   {
      return ((getId() == null) || (getVersion() == null));
   }

   /**
    * it might make sense to ask the question like this in some contexts.
    */
   public boolean cameFromDatabase()
   {
      return !isNew();
   }

   /** 
    * we define equals as having the same id and version, where it makes sense this method
    * should be overridden 
    */
   @Override
   public boolean equals(Object obj)
   {
      if (obj == null)
      {
         return false;
      }

      if (obj instanceof DataTransferObject)
      {
         DataTransferObject dto = (DataTransferObject) obj;
         if ((getId() != null) || (getVersion() != null))
         {
            return ((getId().equals(dto.getId())) && (getVersion().equals(dto.getVersion())));
         }
         else
         {
            if (isNew() && dto.isNew())
            {
               return true;
            }
            return false;
         }

      }
      return false;
   }

   /**
    * again this is based on id and version, if there is a large collection of newed up 
    * DTOs (that have no ID or version) the hashmap performance will break down.  In such 
    * a case you need to override this method.
    */
   @Override
   public int hashCode()
   {
      int result = 17;
      result = 37 * result + (getId() == null ? 0 : getId());
      result = 37 * result + (getVersion() == null ? 0 : getVersion());

      return result;
   }

   /** 
    * this should be overridden with attributes that make sense to the user.  for example
    * a 'name' or 'value' field.
    */
   public int compareTo(DataTransferObject obj)
   {
      DataTransferObject dto = obj;
      return getId().compareTo(dto.getId());
   }

   /**
    * this is stuff we always want to do to String values before we allow the data
    * to be sent to the database.
    */
   protected String cleanStringInput(String stringIn)
   {
      if ((stringIn == null) || "".equals(stringIn.trim()))
      {
         return null;
      }

      // get rid of multiple spaces or spaces in front or back
      StringTokenizer stringTokenizer = new StringTokenizer(stringIn, " ", false);
      String newString = "";
      while (stringTokenizer.hasMoreElements())
      {
         newString += " " + stringTokenizer.nextElement();
      }
      return newString.trim();
   }

   /**
    * this doesn't perform well (uses reflection) but it's primarily used in development.
    */
   @Override
   public String toString()
   {
      return ToStringBuilder.reflectionToString(this);
   }
}
